///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////@

// filajs
// ======
//
// Στο παρόν υπάρχουν δομές, functions, κλάσεις και μέθοδοι που αφορούν στα
// παιγνιόχαρτα. Πιο συγκεκριμένα ορίζονται τα εξής:
//
// filajs (namespace)
// ------------------
// Πρόκειται για το singleton "filajs" το οποίο χρησιμοποιείται ως global namespace
// για όλα τα αντικείμενα (functions, global variables κλπ) που σχετίζονται με τη
// βιβλιοθήκη.
//
// filajsCard (παιγνιόχαρτα OOP)
// -----------------------------
// Η "filajsCard" είναι η σημαντικότερη κλάση της βιβλιοθήκης και παριστά τα ίδια
// τα παιγνιόχαρτα. Η κλάση περιλαμβάνει όλα εκείνα τα properties που καθορίζουν
// ένα παιγνιόχαρτο, ήτοι τη φυλή (χρώμα), την αξία, το joker, το χρώμα πλάτης
// του παιγνιοχάρτου, καθώς επίσης και μεθόδους που αφορούν στα παιγνιόχαρτα.
//
// filajsHand (χαρτωσιές OOP)
// --------------------------
// Η "filajsHand" παριστά χαρτωσιές, ήτοι διατεταγμένες ομάδες παιγνιοχάρτων, π.χ.
// τα φύλλα που μοιράζουμε σε κάθε παίκτη μιας παρτίδας πρέφας, ή τα φύλλα που
// βρίσκονται κλειστά στο τραπέζι σε μια παρτίδα Texas hold 'em. Ακόμη και μια
// ολόκληρη τράπουλα μπορεί να θεωρηθεί ως χαρτωσιά. Η κλάση περιλαμβάνει ένα
// σημαντικό property που είναι το array των παιγνιοχάρτων της χαρτωσιάς και
// αρκετά δευτερεύοντα properties εκ των οποίων τα περισσότερα αφορούν στο
// DOM element της χαρτωσιάς.

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////@

filajs = {
	// Η property "project" περιέχει το όνομα του project που αφορά στη
	// διαχείριση παιγνιοχάρτων.

	project: 'filajs',

	// Η property "author" περιέχει το όνομα του προγραμματιστή που συνέταξε
	// το παρόν και όλα τα υπόλοιπα προγράμματα που αφορούν στο "filajs" API.

	author: 'Panos I. Papadopoulos',

	// Η property "copyright" περιέχει ένα copyright tag που αφορά στον κατέχοντα
	// το copy right του παρόντος και των υπολοίπων αντικειμένων (προγράμματα,
	// βιβλιοθήκες, εικόνες κλπ) που συνιστούν το "filajs" API.

	copyright: 'Copyright by Panos I. Papadopoulos, 2014. All rights reservred.',

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////@

	// Το array "suitArray" περιέχει τις φυλές των παιγνιοχάρτων ως strings,
	// ήτοι "S" για τα μπαστούνια, "D" για τα καρά, "C" για τα σπαθιά και
	// "H" για τις κούπες. Η σειρά είναι αυθαίρετη, αλλά καθορίζει τη σειρά
	// με την οποία ταξινομούνται by default τα φύλλα μιας χαρτωσιάς, επομένως
	// πρέπει να εναλλάσσονται τα χρώματα των φυλών (μαύρο/κόκκινο).

	suitArray: [
		'S',
		'D',
		'C',
		'H',
	],

	// Η λίστα "suitList" δεικτοδοτείται με τις φυλές των παιγνιοχάρτων που
	// περιέχονται στο array "suitArray" και παράγεται κατά την αρχικοποίηση
	// από το εν λόγω array.

	suitList: {},

	suitDesc: {
		S: 'Spades',
		D: 'Diamonds',
		C: 'Clubs',
		H: 'Hearts',
	},

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////@

	// Το array "rankArray" περιέχει τις αξίες των παιγνιοχάρτων ως strings,
	// ήτοι "2", "3",..., "9" για τα παιγνιόχαρτα με αξίες από 2 έως 9, και
	// "T", "J", "Q", "K" και "A" για το 10, τον βαλέ, την ντάμα, τον ρήγα
	// και τον άσο αντίστοιχα. Η σειρά ακολουθεί τη συνήθη πραγματική αξία
	// των παιγνιοχάρτων στα περισσότερα παιχνίδια και καθορίζει τη σειρά
	// με την οποία εμφανίζονται by default τα φύλλα μιας χαρτωσιάς.

	rankArray: [
		'2',
		'3',
		'4',
		'5',
		'6',
		'7',
		'8',
		'9',
		'T',
		'J',
		'Q',
		'K',
		'A',
	],

	// Η λίστα "rankList" δεικτοδοτείται με τις αξίες των παιγνιοχάρτων που
	// περιέχονται στο array "rankArray" και παράγεται κατά την αρχικοποίηση
	// από το εν λόγω array.

	rankList: {},

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////@

	// Η λίστα "backArray" περιέχει τα επιτρεπτά χρώματα πλάτης των παιγνιοχάρτων
	// ως strings.

	backArray: [
		'R',
		'B',
	],

	// Η λίστα "backList" δεικτοδοτείται με τα χρώματα πλάτης των παιγνιοχάρτων
	// ως strings που περιέχονται στο array "backArray" και παράγεται κατά την
	// αρχικοποίηση από το εν λόγω array.

	backList: {
	},

	// Η property "back" δείχνει το default χρώμα της πλάτης των παιγνιοχάρτων.

	back: 'R',

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////@

	// Η property "shuffleFactor" δείχνει πόσες αμοιβαίες εναλλαγές θα γίνουν
	// κατά το ανακάτεμα των φύλλων μιας χαρτωσιάς σε σχέση με το πλήθος των
	// φύλλων της χαρτωσιάς. Αν, π.χ. η χαρτωσιά περιλαμβάνει 52 φύλλα και το
	// "shuffleFactor" είναι 10, θα γίνουν 52x10=520 εναλλαγές.

	shuffleFactor: 10,
};

filajs.projectSet = function(project) {
	filajs.project = project;
	return filajs;
};

filajs.projectGet = function() {
	return filajs.project;
};

filajs.authorSet = function(author) {
	filajs.author = author;
	return filajs;
};

filajs.authorGet = function() {
	return filajs.author;
};

filajs.copyrightSet = function(copyright) {
	filajs.copyright = copyright;
	return filajs;
};

filajs.copyrightGet = function() {
	return filajs.copyright;
};

// Η function "isSuit" δέχεται ένα string και επιστρέφει true εφόσον
// το string παριστά φυλή παιγνιοχάρτου. Ουσιαστικά μιλάμε για τα
// strings "S", "D", "C" και "H".

filajs.isSuit = function(s) {
	return filajs.suitList.hasOwnProperty(s);
};

filajs.notSuit = function(s) {
	return !filajs.isSuit(s);
};

filajs.suitDescGet = function(s) {
	return filajs.suitDesc[s];
};

// Η function "suitWalk" διατρέχει όλες τις φυλές παιγνιοχάρτων και για
// κάθε φυλή καλεί callback function με παράμετρο την ανά χείρας φυλή.
// Η σειρά καθορίζεται από το array "suitArray".

filajs.suitWalk = function(callback) {
	var i;

	for (i = 0; i < filajs.suitArray.length; i++)
	callback(filajs.suitArray[i]);

	return filajs;
};

// Η function "isRank" δέχεται ένα string και επιστρέφει true εφόσον
// το string παριστά αξία παιγνιοχάρτου. Ουσιαστικά πρόκειται για τα
// strings "2", "3", "4", "5", "6", "7", "8", "9", "T", "J", "Q", "K"
// και "A".

filajs.isRank = function(s) {
	return filajs.rankList.hasOwnProperty(s);
};

filajs.notRank = function(s) {
	return !filajs.isRank(s);
};

// Η function "rankWalk" διατρέχει όλες τις αξίες παιγνιοχάρτων και για
// κάθε αξία καλεί callback function με παράμετρο την ανά χείρας αξία.
// Η σειρά καθορίζεται από το array "rankArray".

filajs.rankWalk = function(callback) {
	var i;

	for (i = 0; i < filajs.rankArray.length; i++)
	callback(filajs.rankArray[i]);

	return filajs;
};

// Η function "isJoker" δέχεται ένα string και επιστρέφει true εφόσον
// το string είναι δεκτό ως σύμβολο joker. Ουσιαστικά, το μοναδικό
// δεκτό σύμβολο joker είναι το "J".

filajs.isJoker = function(s) {
	return(s === 'J');
};

filajs.notJoker = function(s) {
	return !filajs.isJoker(s);
};

// Η function "isBack" δέχεται ένα string και επιστρέφει true εφόσον
// το string είναι δεκτό ως χρώμα πλάτης παιγνιοχάρτου. Βασικά μιλάμε
// για τα strings "R" (κόκκινο) και "B" (μπλε).

filajs.isBack = function(rb) {
	return filajs.backList.hasOwnProperty(rb);
};

filajs.notBack = function(rb) {
	return !filajs.isBack(rb);
};

// Η function "backSet" δέχεται ένα χρώμα πλάτης παιγνιοχάρτων ως string
// και θέτει το default χρώμα για τα παιγνιόχαρτα που θα δημιουργηθούν
// εφεξής.

filajs.backSet = function(rb) {
	if (filajs.notBack(rb))
	throw filajs.project + ': ' + rb + ': invalid default back color value';

	filajs.back = rb;
	return filajs;
};

// Η function "backGet" επιστρέφει το default χρώμα πλάτης παιγνιοχάρτων.

filajs.backGet = function() {
	return filajs.back;
};

// Η μέθοδος "shuffleFactorSet" καθρίζει πόσες αμοιβαίες εναλλαγές φύλλων
// γίνονται κατά το ανακάτεμα σε σχέση με το πλήθος των φύλλων της χαρτωσιάς.

filajs.shuffleFactorSet = function(n) {
	if ((typeof n !== 'number') || (n < 0))
	throw filajs.project + ': ' + n + ': invalid default shuffle factor';

	filajs.shuffleFactor = n;
	return filajs;
};

filajs.shuffleFactorGet = function() {
	return filajs.shuffleFactor;
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////@

// filajsCard
// ----------
//
// Ακολουθεί κλάση "filajsCard" που παριστά παιγνιόχαρτα. Πρόκειται για την πλέον
// σημαντική κλάση της βιβλιοθήκης. Τα παιγνιόχαρτα έχουν διάφορες properties,
// σημαντικότερες από τις οποίες είναι:
//
//	suit		Πρόκειται για τη φυλή του παιγνιοχάρτου και παίρνει τιμές
//			"S" (μπαστούνια), "D" (καρά), "C" (σπαθιά) και "H" (κούπες).
//
//	rank		Πρόκειται για την αξία του παιγνιοχάρτου, π.χ. "2" για το
//			δυάρι, "9" για το εννιάρι, "T" για το δεκάρι (ten), "Q" για
//			την ντάμα και "A" για τον άσο.
//
//	joker		Σε περίπτωση που το παιγνιόχαρτο παριστά κάποιο joker,
//			τίθεται η εν λόγω property στο χρώμα του joker ως string,
//			ήτοι "R" (κόκκινο), ή "B" (μαύρο/μπλε).
//
//	back		Το χρώμα πλάτης του παιγνιοχάρτου ως string, ήτοι "R"
//			(κόκκινο), ή "B" (μαύρο). Το χρώμα καθορίζεται αρχικά από
//			το default χρώμα πλάτης παιγνιοχάρτων κατά τη στιγμή της
//			δημιουργίας του παιγνιοχάρτου ως αντικειμένου.
//
//	closed		Η property "closed" δείχνει αν το φύλλο είναι κλειστό ή
//			ανοικτό.

filajsCard = function() {
	var s, r, b;

	// Αρχικά θέτουμε το χρώμα της πλάτης του παιγνιοχάρτου στο τρέχον default
	// χρώμα. Πράγματι, το χρώμα πλάτης των παιγνιοχάρτων καθορίζεται αρχικά
	// από το τρέχον χρώμα πλάτης κατά τη στιγμή της δημιουργίας του παιγνιοχάρτου
	// ως προγραμματιστικού αντικειμένου.

	this.backSet(filajs.backGet());

	// Αν δεν περάσαμε παραμέτρους, το παιγνιόχαρτο θα παραμείνει κενό και ως
	// εκ τούτου απροσδιόριστο.

	if (arguments.length <= 0)
	return this;

	// Έχουμε τη δυνατότητα να περάσουμε λίστα με τα επιθυμητά properties
	// για το νέο παιγνιόχαρτο, π.χ.
	//
	//	filo = new filajsCard({
	//		suit: 'S',
	//		rank: '7',
	//		back: 'B',
	//	});
	//
	// Το ίδιο αποτέλεσμα θα είχαμε ως εξής:
	//
	//	filo = new filajsCard().suitSet('S').rankSet('7').backSet('B');

	if (typeof arguments[0] === 'object') {
		if (arguments.length != 1)
		throw filajs.project + ': excessive arguments';

		for (s in arguments[0]) {
			switch (typeof arguments[0][s]) {
			case 'string':
				this[s] = arguments[0][s];
				break;
			case 'number':
				this[s] = arguments[0][s].toString();
				break;
			}
		}

		return this;
	}

	// Μπορούμε να περάσουμε ΔΥΟ παραμέτρους που να υποδηλώνουν τα εξής:
	//
	//	χρώμα και αξία παιγνιοχάρτου, π.χ. "S", "7"
	//
	//	joker και χρώμα, π.χ. "J", "R"
	//
	// Αν υπάρχει και τρίτη παράμετρος, τότε αυτή πρέπει δηλώνει το χρώμα
	// πλάτης του παιγνιοχάρτου ως "R" ή "B".
	//
	// Μπορούμε, όμως, να περάσουμε και ΜΙΑ παράμετρο, π.χ. "S7", "DA",
	// "JB" κλπ. Αν υπάρχει και τρίτος χαρακτήρας στο string, τότε αυτός
	// υποδηλώνει το χρώμα της πλάτης του παιγνιοχάρτου, π.χ. "C3R" για
	// το τρία σπαθί με κόκκινη πλάτη.

	if (arguments.length === 1) {
		s = arguments[0].substr(0, 1);
		r = arguments[0].substr(1, 1);
		b = arguments[0].substr(2, 1);

		if (s.filajsIsJoker())
		this.jokerSet(r);

		else
		this.suitSet(s).rankSet(r);

		if (b.filajsIsBack())
		this.backSet(b);

		return this;
	}

	if (arguments[0].filajsIsJoker())
	this.jokerSet(arguments[1]);

	else
	this.suitSet(arguments[0]).rankSet(arguments[1]);

	if (arguments.length < 3)
	return this;

	if (arguments.length > 3)
	throw filajs.project + ': excessive arguments';

	this.backSet(arguments[2]);

	return this;
};

filajsCard.prototype.suitSet = function(suit) {
	if (filajs.notSuit(suit))
	throw filajs.project + ': ' + suit + ': invalid suit value';

	this.suit = suit;
	return this;
};

filajsCard.prototype.suitGet = function() {
	return this.suit;
};

filajsCard.prototype.rankSet = function(rank) {
	if (filajs.notRank(rank))
	throw filajs.project + ': ' + rank + ': invalid rank value';

	this.rank = rank;
	return this;
};

filajsCard.prototype.rankGet = function() {
	return this.rank;
};

filajsCard.prototype.jokerSet = function(rb) {
	switch (rb) {
	case 'R':
	case 'B':
		this.joker = rb;
		return this;
	}

	throw filajs.project + ': ' + rb + ': invalid joker color value';
};

filajsCard.prototype.jokerGet = function() {
	return this.joker;
};

filajsCard.prototype.isJoker = function() {
	return this.joker;
};

filajsCard.prototype.notJoker = function() {
	return !this.isJoker();
};

filajsCard.prototype.backSet = function(rb) {
	if (filajs.notBack(rb))
	throw filajs.project + ': ' + rb + ': invalid back color value';

	this.back = rb;
	return this;
};

filajsCard.prototype.backGet = function() {
	return this.back;
};

filajsCard.prototype.backSwitch = function() {
	this.backSet(this.backGet().filajsBackSwitch());
	return this;
};

filajsCard.prototype.faceSet = function(on) {
	this.closed = !on;
	return this;
};

filajsCard.prototype.faceDown = function() {
	this.closed = true;
	return this;
};

filajsCard.prototype.faceUp = function() {
	delete this.closed;
	return this;
};

filajsCard.prototype.switchFace = function() {
	if (this.isFaceDown())
	this.faceUp();

	else
	this.faceDown();

	return this;
};

filajsCard.prototype.isFaceDown = function() {
	return this.closed;
};

filajsCard.prototype.isFaceUp = function() {
	return !this.isFaceDown();
};

// Η μέθοδος "toString" μετατρέπει τις βασικές properties το παιγνιοχάρτου
// σε ένα ενιαίο string.

filajsCard.prototype.toString = function(img) {
	if (img) {
		if (this.isFaceDown())
		return 'B' + this.backGet();
	}

	if (this.isJoker())
	return 'J' + this.jokerGet();

	return this.suitGet() + this.rankGet();
};

// Η μέθοδος "suitLike" επιστρέφει true εφόσον το ανά χείρας φύλλο είναι της
// ιδίας φυλής με το φύλλο που περνάμε ως παράμετρο.

filajsCard.prototype.suitLike = function(card) {
	var s;

	s = this.suitGet();
	if (!s)
	return false;

	return(s === card.suitGet());
};

filajsCard.prototype.suitUnlike = function(card) {
	return !this.suitLike(card);
};

// Η μέθοδος "colorLike" επιστρέφει true εφόσον η φυλή του ανά χείρας φύλλου είναι
// του ιδίου χρώματος με τη φυλή του φύλλου που περνάμε ως παράμετρο. Ουσιαστικά
// η μέθοδος επιστρέφει true αν τα φύλλα είναι ομοιόχρωμα (και τα δύο κόκκινα, ή
// και τα δύο μαύρα).

filajsCard.prototype.colorLike = function(card) {
	var s1, s2;

	if (this.isJoker())
	return(this.jokerGet() === card.jokerGet());

	s1 = this.suitGet();
	if (!s1)
	return false;

	s2 = card.suitGet();
	if (!s2)
	return false;

	try {
		return((filajs.suitList[s1] % 2) === (filajs.suitList[s2] % 2));
	}
	catch (e) {
		return false;
	}
};

filajsCard.prototype.colorUnlike = function(card) {
	return !this.colorLike(card);
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////@
// TODO Ελέγθηκε ο κώδικας μέχρι εδώ (21/01/2015)
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////@

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////@

// Η κλάση "filajsHand" παριστά τις χαρτωσιές, δηλαδή διατεταγμένες ομάδες
// παιγνιοχάρτων. Ουσιαστικά πρόκειται για ένα array παιγνιοχάρτων.
//
// Κατά τη δημιουργία μιας χαρτωσιάς μπορούμε να περάσουμε τη χαρτωσιά ως ένα
// μεγάλο string με τα φύλλα να καθορίζονται όσον αφορά στις φυλές και στις
// αξίες, π.χ. "C2HTHAC5JBDKDQS7S8SJ". Μπορούμε, επίσης, να περάσουμε μεμονωμένα
// φύλλα, ή ακόμη και άλλες χαρτωσιές. Μπορούν να γίνουν και συνδυασμοί των
// παραπάνω μεθόδων, αλλά δεν συνιστάται. Τα properties μιας χαρτωσιάς είναι:
//
//	cardArray	Είναι το array των φύλλων της χαρτωσιάς.

filajsHand = function() {
	var i, j;

	this.cardArray = [];

	for (i = 0; i < arguments.length; i++) {
		switch (typeof arguments[i]) {
		case 'string':
			for (j = 0; j < arguments[i].length; j += 2)
			this.cardPush(new filajsCard(arguments[i].substr(j, 2)));
			break;
		case 'object':
			if (arguments[i] instanceof filajsCard)
			this.cardPush(arguments[i]);

			else if (arguments[i] instanceof filajsHand)
			this.handPush(arguments[i]);

			else
			throw filajs.project + ': ' + arguments[i] + ': invalid argument';
			break;
		default:
			throw filajs.project + ': ' + arguments[i] + ': invalid argument type';
		}
	}
};

filajsHand.prototype.cardSet = function(n, card) {
	this.cardArray[n] = card;
	return this;
};

filajsHand.prototype.cardGet = function(n) {
	return this.cardArray[n];
};

filajsHand.prototype.cardPush = function(card) {
	this.cardArray.push(card);
	return this;
};

filajsHand.prototype.cardPop = function(card) {
	return this.cardArray.pop();
};

filajsHand.prototype.cardsCount = function() {
	return this.cardArray.length;
};

filajsHand.prototype.handPush = function(hand) {
	var x = this;

	hand.cardWalk(function() {
		x.cardPush(this);
	});

	return this;
};

// Η μέθοδος "cardWalk" επισκέπτεται με τη σειρά τα φύλλα μιας χαρτωσιάς και
// για κάθε φύλλο καλεί callback function ως μέθοδο του φύλλου με παράμετρο
// το index του συγκεκριμένου φύλλου στη χαρτωσιά.
//
// Μπορούμε να καθορίσουμε και indices αρχής (from) και τέλους (to) ως δεύτερη
// και τρίτη παράμετρο [from, to).

filajsHand.prototype.cardWalk = function(callback, from, to) {
	if (from === undefined)
	from = 0;

	if (to === undefined)
	to = this.cardArray.length;

	for (; from < to; from++)
	callback.call(this.cardArray[from], from);

	return this;
};

// Η μέθοδος "sort" ταξινομεί τα φύλλα της χαρτωσιάς κατά χρώμα και τάξη. Τα
// jokers θεωρούνται ανώτερα από οποιοδήποτε κανονικό φύλλο και μεταξύ τους
// ταξινομούνται κατά χρώμα.

filajsHand.prototype.sort = function() {
	this.cardArray.sort(function(c1, c2) {
		var x1, x2;

		x1 = c1.jokerGet();
		if (x1) {
			x2 = c2.jokerGet();
			if (!x2)
			return 1;

			if (x1 < x2)
			return -1;

			if (x1 > x2)
			return 1;

			return 0;
		}

		x2 = c2.jokerGet();
		if (x2)
		return -1;

		x1 = filajs.suitList[c1.suitGet()];
		if (!x1)
		x1 = 0;

		x2 = filajs.suitList[c2.suitGet()];
		if (!x2)
		x2 = 0;

		if (x1 < x2)
		return -1;

		if (x1 > x2)
		return 1;

		x1 = filajs.rankList[c1.rankGet()];
		if (!x1)
		x1 = 0;

		x2 = filajs.rankList[c2.rankGet()];
		if (!x2)
		x2 = 0;

		if (x1 < x2)
		return -1;

		if (x1 > x2)
		return 1;

		return 0;
	});

	return this;
};

// Η μέθοδος "shuffle" ανακατεύει τα φύλλα της χαρτωσιάς επιτελώντας πληθώρα
// αμοιβαίων εναλλαγών μεταξύ τυχαίων φύλλων της χαρτωσιάς. Το πλήθος των
// εναλλαγών μπορεί να καθοριστεί με παράμετρο, αλλά by default προκύπτει
// από το πλήθος των φύλλων της χαρτωσιάς πολλαπλασιασμένο επί κάποιον
// συντελεστή που καθορίζεται γενικά από το "filajs.shuffleFactor".

filajsHand.prototype.shuffle = function(n) {
	var l, i, j, f;

	l = this.cardsCount();
	if (!l)
	return this;

	if (n === undefined)
	n = l * filajs.shuffleFactor;

	while (n-- > 0) {
		i = Math.floor(Math.random() * l);
		j = Math.floor(Math.random() * l);
		if (i === j)
		continue;

		f = this.cardGet(i);
		this.cardSet(i, this.cardGet(j));
		this.cardSet(j, f);
	}

	return this;
};

// Η μέθοδος "slice" επιστρέφει νέα χαρτωσιά αποτελούμενη από τα φύλλα της
// ανά χείρας χαρτωσιάς που καθορίζονται ως παράμετροι. Η πρώτη παράμετρος
// δείχνει το πρώτο φύλλο (0 based, default 0) και ακολουθεί το πλήθος των
// φύλλων (default όλα τα φύλλα).
//
// WARNING: Η μέθοδος ΔΕΝ αποσπά τα φύλλα από την ανά χείρας χαρτωσιά, τα
// δε φύλλα της επιστρεφόμενης χαρτωσιάς είναι κοινά με τα φύλλα της ανά
// χείρας χαρτωσιάς, ως προγραμματιστικά αντικείμενα.

filajsHand.prototype.slice = function(from, count) {
	var len, x;

	if (from === undefined)
	from = 0;

	else if ((typeof from !== 'number') || (from !== parseInt(from)) || (from < 0))
	throw filajs.project + ': ' + from + ': invalid argument';

	len = this.cardsCount();
	x = new filajsHand();

	if (from >= len)
	return x;

	len -= from;

	if (count === undefined)
	count = len;

	else if ((typeof count !== 'number') || (count !== parseInt(count)) || (count < 0))
	throw filajs.project + ': ' + count + ': invalid argument';

	else if (count > len)
	count = len;

	x.cardArray = this.cardArray.slice(from, from + count);

	return x;
};

// Η μέθοδος "extract" αποσπά ένα ή περισσότερα φύλλα από τη χαρτωσιά και
// επιστρέφει νέα χαρτωσιά αποτελούμενη από τα αποσπασμένα φύλλα.
 
filajsHand.prototype.extract = function(from, count) {
	var len, x;

	if (from === undefined)
	from = 0;

	else if ((typeof from !== 'number') || (from !== parseInt(from)) || (from < 0))
	throw filajs.project + ': ' + from + ': invalid argument';

	x = new filajsHand();
	len = this.cardsCount();

	if (from >= len)
	return x;

	len -= from;

	if (count === undefined)
	count = len;

	else if ((typeof count !== 'number') || (count !== parseInt(count)) || (count < 0))
	throw filajs.project + ': ' + count + ': invalid argument';

	else if (count > len)
	count = len;

	x.cardArray = this.cardArray.splice(from, count);

	return x;
};

filajsHand.prototype.toString = function(img) {
	var s = '';

	this.cardWalk(function() {
		s += this.toString(img);
	});

	return s;
};

// Η function "filajsDeck" είναι ιδιαίτερη με την έννοια ότι δημιουργεί μια
// νέα χαρτωσιά. Σκοπός της function είναι η δημιουργία τράπουλας, η οποία
// κατ' ουσίαν είναι μια χαρτωσιά που περιέχει όλα τα φύλλα της τράπουλας.
// Η function επιτρέπει τη δημιουργία περιορισμένης τράπουλας, π.χ. τράπουλα
// για πρέφα όπου θα περιλαμβάνονται τα φύλλα 7, 8, 9, 10, J, Q, K και A.
// Παρέχεται, επίσης, η δυνατότητα συμπερίληψης οποιουδήποτε αριθμού joker,
// δυνατότητα καθορισμού του χρώματος πλάτης των φύλλων και η πολλαπλότητα
// μέσω της οποίας μπορούμε να δημιουργήσουμε π.χ. τράπουλα για blackjack
// αποτελούμενη από 6 κανονινκές τράπουλες των 52 φύλλων.
//
// Από τη στιγμή που η function επιστρέφει η ίδια μια νέα χαρτωσιά, μπορεί
// να κληθεί με δυο τρόπους:
//
//	deck = filajsDeck();		/* I prefer that */
//
//	deck = new filajsDeck();	/* maybe more readable */
//
// Αναφέρουμε ένα παράδειγμα με το οποίο δημιουργούμε τράπουλα αποτελούμενη
// από δύο κανονικές τράπουλες των 52 φύλλων. Στην τράπουλα θέλουμε, επίσης,
// να περιλαμβάνονται δύο joker, το δε χρώμα πλάτης των φύλλων της τράπουλας
// να είναι κόκκινο. Θέλουμε, τέλος, η τράπουλα να είναι ανακατεμένη:
//
//	deck = new filajsDeck({
//		multi: 2,
//		joker: 2,
//		back: 'B',
//	}).shuffle();

filajsDeck = function(opts) {
	var xartosia, i, j;

	// Ελέγχουμε και συμπληρώνουμε τις παραμέτρους δημιουργίας της
	// τράπουλας.

	if (opts === undefined)
	opts = {};

	// Χρησιμοποιούμε τη λίστα αξιών προκειμένου να εντοπίσουμε το
	// «μικρότερο» φύλλο της υπό κατασκευήν τράπουλας (default 2).

	opts.min = filajs.rankList[opts.min];
	if (!opts.min)
	opts.min = filajs.rankList['2'];

	// Χρησιμοποιούμε τη λίστα αξιών προκειμένου να εντοπίσουμε το
	// «μεγαλύτερο» φύλλο της υπό κατασκευήν τράπουλας (default άσος).

	opts.max = filajs.rankList[opts.max];
	if (!opts.max)
	opts.max = filajs.rankList['A'];

	// Αν δεν έχουν καθοριστεί joker, η τράπουλα δεν θα περιέχει joker.

	if (!opts.hasOwnProperty('joker'))
	opts.joker = 0;

	// Αν δεν έχει καθοριστεί χρώμα πλάτης των παιγνιοχάρτων, τότε
	// χρωματίζουμε με το τρέχον default χρώμα πλάτης παιγνιοχάρτων.

	if (!opts.hasOwnProperty('back'))
	opts.back = filajs.backGet();

	// Η παράμετρος "multi" χρησιμοποιείται σε διπλές, τριπλές κλπ τράπουλες.
	// By default παράγεται απλή τράπουλα.

	if (!opts.hasOwnProperty('multi'))
	opts.multi = 1;

	xartosia = new filajsHand();
	for (i = 0; i < opts.multi; i++)
	filajs.suitWalk(function(suit) {
		for (j = opts.min - 1; j < opts.max; j++)
		xartosia.cardPush(new filajsCard(suit, filajs.rankArray[j]).backSet(opts.back));
	});

	for (i = 0; i < opts.joker; i++)
	xartosia.cardPush(new filajsCard('J', i % 2 ? 'R' : 'B').backSet(opts.back));

	return xartosia;
};

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////@

// Η μέθοδος "filajsIsSuit" ελέγχει αν το ανά χείρας string είναι
// δεκτό ως φυλή παιγνιοχάρτου.

String.prototype.filajsIsSuit = function() {
	return filajs.isSuit(this.valueOf());
};

String.prototype.filajsNotSuit = function() {
	return !this.filajsIsSuit();
};

// Η μέθοδος "filajsSuitDesc" δέχεται μια φυλή παιγνιοχάρτου και επιστρέφει
// την περιγραφή της φυλής.

String.prototype.filajsSuitDesc = function() {
	return filajs.suitDescGet(this.valueOf());
};

// Η μέθοδος "filajsIsRank" ελέγχει αν το ανά χείρας string είναι
// δεκτό ως αξία παιγνιοχάρτου.

String.prototype.filajsIsRank = function() {
	return filajs.isRank(this.valueOf());
};

String.prototype.filajsNotRank = function() {
	return !this.filajsIsRank();
};

// Η μέθοδος "filajsIsJoker" ελέγχει αν το ανά χείρας string είναι
// δεκτό ως σύμβολο joker. Ουσιαστικά ελέγχεται αν το ανά χείρας
// string είναι το "J".

String.prototype.filajsIsJoker = function() {
	return filajs.isJoker(this.valueOf());
};

String.prototype.filajsNotJoker = function() {
	return !this.filajsIsJoker();
};

// Η μέθοδος "filajsToCard" επιστρέφει το ανά χείρας string ως παιγνιόχαρτο
// της τράπουλας.

String.prototype.filajsToCard = function() {
	return new filajsCard(this.valueOf());
};

// Η μέθοδος "filajsToHand" επιστρέφει το ανά χείρας string ως χαρτωσιά.

String.prototype.filajsToHand = function() {
	return new filajsHand(this.valueOf());
};

// Η μέθοδος "filajsIsBack" ελέγχει αν το ανά χείρας string είναι
// δεκτό ως χρώμα πλάτης παγνιοχάρτου.

String.prototype.filajsIsBack = function() {
	return filajs.backList[this.valueOf()];
};

String.prototype.filajsNotBack = function() {
	return !this.filajsIsBack();
};

// Η μέθοδος "filajsBackSwitch" επιστρέφει το ανάποδο χρώμα πλάτης από αυτό
// που δείχνει το ανά χείρας string.

String.prototype.filajsBackSwitch = function() {
	return(this.valueOf() === 'R' ? 'B' : 'R');
};


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////@

// Η function που ακολουθεί καλείται on the fly και επιτελεί εργασίες
// αρχικοποίησης.

(function() {
	var i;

	// Δημιουργείται η λίστα "suitList" από το array "suitArray".

	i = 0;
	filajs.suitWalk(function(suit) {
		filajs.suitList[suit] = ++i;
	});

	// Δημιουργείται η λίστα "rankList" από το array "rankArray".

	i = 0;
	filajs.rankWalk(function(rank) {
		filajs.rankList[rank] = ++i;
	});

	// Δημιουργείται η λίστα "backList" από το array "backArray".

	for (i = 0; i < filajs.backArray.length; i++) {
		filajs.backList[filajs.backArray[i]] = i;
	}
})();
